package org.javaforever.gatescore.compiler;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
import org.javaforever.gatescore.core.FrontDomain;
import org.javaforever.gatescore.core.FrontDropdown;
import org.javaforever.gatescore.core.FrontField;
import org.javaforever.gatescore.core.FrontManyToMany;
import org.javaforever.gatescore.core.FrontPrism;
import org.javaforever.gatescore.core.FrontProject;
import org.javaforever.gatescore.core.FrontType;
import org.javaforever.gatescore.core.Pair;
import org.javaforever.gatescore.core.ValidateInfo;
import org.javaforever.gatescore.exception.ValidateException;
import org.javaforever.gatescore.utils.DomainUtil;
import org.javaforever.gatescore.utils.StringUtil;

public class SGSCompiler {
	protected final static String[] forbiddenwords = { "abstract", "assert", "boolean", "break", "byte", "case",
			"catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends",
			"final", "finally", "float", "for", "if",

			"implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private",
			"protected", "public", "return", "short", "static", "strictfp", "super", "switch",

			"synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "byValue",
			"cast", "false", "future", "generic", "inner", "operator", "outer", "rest", "true", "var", "goto", "const",
			"null" };

	protected final static String[] sqlKeyWords = { "alter", "and", "as", "asc", "between", "by", "count", "create",
			"delete", "desc", "distinct", "drop", "from", "group", "having", "in", "insert", "into", "is", "join",
			"like", "not", "on", "or", "order", "select", "set", "table", "union", "update", "values", "where", "limit",
			"bool", "boolean", "bit", "blob", "enum", "long", "longblob", "longtext", "medium", "mediumblob",
			"mediumint", "mediumtext", "time", "timestamp", "tinyblob", "tinyint", "tinytext", "text", "bigint", "int",
			"int1", "int2", "int3", "int4", "int8", "integer", "float", "float4", "float8", "double", "char",
			"varbinary", "varchar", "varcharacter", "precision", "real", "date", "datetime", "year", "unsigned",
			"signed", "decimal", "numeric", "false", "true", "null", "unknown", "date", "time", "timestamp" };

	public static boolean isSqlKeyword(String notion) {
		for (String word : sqlKeyWords) {
			if (word.equals(notion))
				return true;
		}
		return false;
	}

	public static boolean isForbidden(String notion) {
		for (String word : forbiddenwords) {
			if (word.equals(notion))
				return true;
		}
		return false;
	}

	public SGSCompiler() {
	}

	public static FrontProject translate(String sgs, boolean ignoreWarning) throws ValidateException, Exception {
		try {
			if (containsRoundAndSquareBrackets(sgs)) {
				throw new ValidateException("源码中存在圆括号或方括号。");
			}
			List<String> notions = parseNotions(sgs);
			FrontProject project = notionsToFrontProject(notions, ignoreWarning);
			project.setSgsSource(sgs);
			return project;
		} catch (ValidateException e) {
			ValidateInfo info = e.getValidateInfo();
			throw e;
		}
	}

	public static List<String> parseNotions(String sgs) {
		return SGSTokenizer.generateTokens(sgs);
	}

	public static FrontProject notionsToFrontProject(List<String> notions, boolean ignoreWarning)
			throws ValidateException, Exception {
		FrontProject project;
		boolean headFinish = false;
		Stack<String> projectStack = new Stack<String>();
		int domainCount = countFrontDomains(notions);
		for (int i = 0; i < notions.size(); i++) {
			if ("project".equals(notions.get(i))) {
				project = new FrontProject();
				if (!isKeyword(notions.get(i + 1))) {
					String mydbname0 = notions.get(i + 1);
					project.setStandardName(mydbname0);
					project.setTechnicalstack("smeu");
					if ("{".equals(notions.get(i + 2))) {
						projectStack.push("{");
						for (int j = i + 3; j < notions.size(); j++) {
							int inj = j;
							j = scanProjectParams(project,notions,j);							

							if ("domain".equals(notions.get(j)) || "datadomain".equals(notions.get(j))
									|| "prism".equals(notions.get(j))) {
								headFinish = true;
							}
							if (headFinish) {
								List<String> subNotions = notions.subList(j, notions.size());
								List<FrontDomain> domainList = parseFrontDomains(subNotions, projectStack);
								decorateFrontDropdowns(domainList);
								decorateFrontManyToManySlaves(domainList);

								ValidateInfo info0 = validateFrontDomains(domainList);
								if (info0 != null && info0.getCompileErrors() != null
										&& info0.getCompileErrors().size() > 0) {
									throw new ValidateException(info0);
								} else if (info0 != null && ignoreWarning == false && info0.getCompileWarnings() != null
										&& info0.getCompileWarnings().size() > 0) {
									throw new ValidateException(info0);
								}
								if (locateCallMagic(notions.subList(j, notions.size()))) {
									return callMagic(project, domainList);
								}
								if (domainList != null && domainList.size() == domainCount) {
									List<FrontPrism> prismList = parseFrontPrisms(notions.subList(j, notions.size()),
											projectStack, domainList);
									
									project.setDomains(domainList);
									project.setPrisms(prismList);
									return project;
								}
							}
							if (inj != j) j--;
						}
					}
				}
			}
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("将片断缀合成项目错误。");
		throw new ValidateException(info);
	}
	
	private static int scanProjectParams(FrontProject project,List<String> notions, int j) {
		int retVal = j;
		if ("packagetoken".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2))) {
				String packagetoken = notions.get(j + 2);
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("dbprefix".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("dbusername".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1))) {
				String mydbusername = notions.get(j + 2);
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("dbpassword".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1))) {
				String mydbpassword = notions.get(j + 2);
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("dbname".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1))) {
				String mydbname = notions.get(j + 2);									
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("dbtype".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1))) {
				String mydbtype = notions.get(j + 2);
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("emptypassword".equals(notions.get(j))) {
			if (";".equals(notions.get(j + 1)))
				retVal = j + 2;
		}

		if ("technicalstack".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2))){
				project.setTechnicalstack(notions.get(j + 2));
				if (project.getTechnicalstack().toLowerCase().equals("jeeeu")||project.getTechnicalstack().toLowerCase().equals("mjeeeu")) {
					project.setUseController(true);
				}
			}
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("title".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
				project.setTitle(notions.get(j + 2));
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("subtitle".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
				project.setSubTitle(notions.get(j + 2));
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("footer".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
				project.setFooter(notions.get(j + 2));
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}

		if ("crossorigin".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}
		
		if ("resolution".equals(notions.get(j))) {
			if (":".equals(notions.get(j + 1)) && !isKeyword(notions.get(j + 2)))
			if (";".equals(notions.get(j + 3)))
				retVal = j + 4;
		}
		return retVal;
	}

	public static List<FrontPrism> parseFrontPrisms(List<String> notions, Stack<String> projectStack, List<FrontDomain> domainList) throws ValidateException, Exception {
			List<FrontPrism> list = new ArrayList<FrontPrism>();
			FrontPrism prism = new FrontPrism();
			boolean prismStackjOverflow = false;
			Stack<String> prismStack = new Stack<String>();
			boolean started = false;
			int totalFrontPrismCounts = countFrontPrisms(notions);

			for (int i = 0; i < notions.size(); i++) {
				if (!"prism".equals(notions.get(i))) {
					notions.remove(i);
					i = i - 1;
				} else {
					break;
				}
			}

			for (int i = 0; i < notions.size(); i++) {

				if ("prism".equals(notions.get(i))) {
					prism = new FrontPrism();
					if (!isKeyword(notions.get(i + 1))) {
						prism.setStandardName(notions.get(i + 1));
					}
					if ("{".equals(notions.get(i + 2))) {
						prismStack.push("{");
						projectStack.push("{");
					}
					i = i + 3;
				}

				if ("{".equals(notions.get(i))) {
					if (!prismStackjOverflow) {
						prismStack.push("{");
					} else {
						prismStackjOverflow = false;
					}
					projectStack.push("{");
				}

				if ("}".equals(notions.get(i))) {
					if (!prismStack.empty()) {
						prismStack.pop();
					} else {
						prismStackjOverflow = true;
					}
					projectStack.pop();
				}

				if (prismStack.empty() && list.size() < totalFrontPrismCounts) {
					list.add(prism);
				} else if (prismStack.empty() && list.size() == totalFrontPrismCounts) {
					for (FrontPrism p : list) {
						Set<Pair> mtmSlaveNames = new TreeSet<Pair>();
						for (FrontManyToMany mtm : p.getDomain().getManyToManies()) {
							mtmSlaveNames.add(new Pair(p.getDomain().getStandardName(), mtm.getManyToManySalveName()));
						}
						p.setManyToManySlaveNames(mtmSlaveNames);
						p.setProjectDomains(domainList);
					}
					return list;
				}

				if ("prismdomain".equals(notions.get(i))) {
					if (":".equals(notions.get(i + 1))) {
						if (!isKeyword(notions.get(i + 2))) {
							FrontDomain d = findFrontDomainFromListByStandardName(domainList, notions.get(i + 2));
							d.decorateDomainWithLabels();
							if (d != null)
								prism.setDomain(d);
							prism.setProjectDomains(domainList);
							prism.generatePrismFromDomain();
							i = i + 2;
							started = true;
						}
					}
				}
			}
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("解析棱柱错误。");
			throw new ValidateException(info);
	}

	public static FrontDomain findFrontDomainFromListByStandardName(List<FrontDomain> domainList, String standardName)
			throws ValidateException {
		for (FrontDomain d : domainList) {
			if (d.getStandardName().equals(standardName))
				return d;
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("在域对象列表找不到域对象" + standardName + "。");
		throw new ValidateException(info);
	}
	
	public static FrontDomain findFrontDomainFromListByAliasOrName(List<FrontDomain> domainList, String aliasOrName)
			throws ValidateException {
		for (FrontDomain d : domainList) {
			if (d.getAliasOrName().equals(aliasOrName))	return d;
			for (FrontManyToMany mtm:d.getManyToManies()) {
				FrontDomain dd = mtm.getSlave();
				if (dd!=null&& dd.getAliasOrName().equals(aliasOrName)) return dd;
			}
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("在域对象列表找不到域对象" + aliasOrName + "。");
		throw new ValidateException(info);
	}

	public static List<FrontDomain> parseFrontDomains(List<String> notions, Stack<String> projectStack)
			throws ValidateException {
		List<FrontDomain> list = new ArrayList<FrontDomain>();
		FrontDomain domain = new FrontDomain();
		boolean domainStackjOverflow = false;
		Stack<String> domainStack = new Stack<String>();
		int totalFrontDomainCounts = countFrontDomains(notions);

		for (int i = 0; i < notions.size(); i++) {
			if ("call".equals(notions.get(i))) {
				if ("magic".equals(notions.get(i + 1)) && ";".equals(notions.get(i + 2))) {
					for (FrontDomain d : list)
						d.decorateDomainWithLabels();
					return list;
				}
			}

			if ("domain".equals(notions.get(i))) {
				domain = new FrontDomain();
				if (isForbidden(notions.get(i + 1))) {
					ValidateInfo info = new ValidateInfo();
					info.addCompileError("使用了被禁止的单词:" + notions.get(i + 1));
					throw new ValidateException(info);
				}
				if (isSqlKeyword(notions.get(i + 1))) {
					ValidateInfo info = new ValidateInfo();
					info.addCompileError("使用了SQL关键字" + notions.get(i + 1));
					throw new ValidateException(info);
				}
				if (!isKeyword(notions.get(i + 1))) {
					domain.setStandardName(notions.get(i + 1));
				}
				if ("{".equals(notions.get(i + 2))) {
					domainStack.push("{");
					projectStack.push("{");
				}
				i = i + 3;
				// continue;
			}

			if ("{".equals(notions.get(i))) {
				if (!domainStackjOverflow) {
					domainStack.push("{");
				} else {
					domainStackjOverflow = false;
				}
				projectStack.push("{");
				// continue;
			}

			if ("}".equals(notions.get(i))) {
				if (!domainStack.empty()) {
					domainStack.pop();
				} else {
					domainStackjOverflow = true;
				}
				projectStack.pop();
				// continue;
				if (domainStack.empty() && domainStackjOverflow == false && list.size() < totalFrontDomainCounts) {
					list.add(domain);
				}
				if (domainStack.empty() && list.size() == totalFrontDomainCounts) {
					return list;
				}
			}

			if ("domainid".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& !isKeyword(notions.get(i + 3))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					FrontField f = new FrontField();
					f.setFieldName(notions.get(i + 2));
					f.setFieldType(new FrontType(notions.get(i + 3)));
					domain.setDomainId(f);
					i += 3;
					continue;
				}
			}

			if ("domainname".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& !isKeyword(notions.get(i + 3))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					FrontField f = new FrontField();
					f.setFieldName(notions.get(i + 2));
					f.setFieldType(new FrontType("String"));
					domain.setDomainName(f);
					i += 3;
					continue;
				}
			}

			if ("activefield".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& !isKeyword(notions.get(i + 3))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					FrontField f = new FrontField();
					f.setFieldName(notions.get(i + 2));
					f.setFieldType(new FrontType("boolean"));
					domain.setActive(f);
					i += 3;
					continue;
				}
			}

			if ("plural".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& !isKeyword(notions.get(i + 3))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					String plural = notions.get(i + 2);
					domain.setPlural(plural);
					i += 3;
					continue;
				}
			}

			if ("domainlabel".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					String label = notions.get(i + 2);
					domain.setLabel(label);
					i += 3;
					continue;
				}
			}

			if ("field".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2)) && !isKeyword(notions.get(i + 3))
						&& ";".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i + 2))) {
						throw new ValidateException("字段" + notions.get(i + 2) + "未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i + 2), 1)) {
						throw new ValidateException("字段" + notions.get(i + 2) + "第二个字母未使用小写英文字母！");
					}
					FrontField f = new FrontField(notions.get(i + 2),notions.get(i + 2), notions.get(i + 3));
					domain.addField(f);
					i += 3;
				} else if (!isKeyword(notions.get(i + 4)) && !";".equals(notions.get(i + 4))
						&& !"}".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i + 2))) {
						throw new ValidateException("字段" + notions.get(i + 2) + "未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i + 2), 1)) {
						throw new ValidateException("字段" + notions.get(i + 2) + "第二个字母未使用小写英文字母！");
					}
					FrontField f = new FrontField(notions.get(i + 2), notions.get(i + 2),notions.get(i + 3));
					domain.addField(f);

					i += 2;
				}
				continue;
			}

			if ("dropdown".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2)) && !isKeyword(notions.get(i + 3))
						&& ";".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isForbidden(notions.get(i + 3))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 3));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 3))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 3));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i + 3))) {
						throw new ValidateException("字段" + notions.get(i + 3) + "未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i + 3), 1)) {
						throw new ValidateException("字段" + notions.get(i + 3) + "第二个字母未使用小写英文字母！");
					}
					FrontDropdown dp = new FrontDropdown(notions.get(i + 2));
					dp.setAliasName(notions.get(i + 3));
					dp.setFieldName(dp.getAliasName());
					domain.addField(dp);

					i += 3;
				}
				continue;
			}

			if ("labelfield".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2)) && !isKeyword(notions.get(i + 3))
						&& ";".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					domain.putFieldLabel(notions.get(i + 2), notions.get(i + 3));
					i += 3;
				}
				continue;
			}
			
			if ("manytomanyslavelabel".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2)) && !isKeyword(notions.get(i + 3))
						&& ";".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					domain.putMtmLabel(notions.get(i + 2), notions.get(i + 3));
					i += 3;
				}
				continue;
			}

			if ("manytomanyslave".equals(notions.get(i))) {
				if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& ";".equals(notions.get(i + 3))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					domain.addManyToMany(new FrontManyToMany(domain.getStandardName(),notions.get(i + 2)));
					i += 2;
				} else if (notions.get(i + 1).equals(":") && !isKeyword(notions.get(i + 2))
						&& !";".equals(notions.get(i + 3)) && ";".equals(notions.get(i + 4))) {
					if (isForbidden(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 2))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 2));
						throw new ValidateException(info);
					}
					if (isForbidden(notions.get(i + 3))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词：" + notions.get(i + 3));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i + 3))) {
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字：" + notions.get(i + 3));
						throw new ValidateException(info);
					}
					FrontManyToMany mtm = new FrontManyToMany(domain.getStandardName(),notions.get(i + 2));
					mtm.setSlaveAlias(notions.get(i + 3));
					domain.addManyToMany(mtm);

					i += 3;
				}
				continue;
			}

			if (";".equals(notions.get(i)))
				continue;
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("解析域对象错误。");
		throw new ValidateException(info);
	}

	public static List<String> clipDataFrontDomainNotions(List<String> notions) {
		List<String> results = new ArrayList<String>();
		boolean started = false;
		for (int i = 0; i < notions.size(); i++) {
			if ("datadomain".equals(notions.get(i))) {
				started = true;
			} else if ("prism".equals(notions.get(i)) || "call".equals(notions.get(i))) {
				started = false;
			}
			if (started)
				results.add(notions.get(i));
		}
		return results;
	}

	public static List<FrontDomain> parseDataFrontDomains(List<FrontDomain> targetFrontDomains, List<String> notions, String packageToken,
			String dbPrefix, List<FrontDomain> domainList) throws ValidateException {
		List<FrontDomain> list = new ArrayList<FrontDomain>();
		FrontDomain domain = new FrontDomain();
		boolean domainStackjOverflow = false;
		Stack<String> domainStack = new Stack<String>();
		boolean datadomainStart = false;
		List<String> notions2 = clipDataFrontDomainNotions(notions);

		if (notions2 == null || notions2.size() == 0) {
			return list;
		}

		for (int i = 0; i < notions2.size(); i++) {
			if ("datadomain".equals(notions2.get(i))) {
				String domainName = notions2.get(i + 1);
				domain = (FrontDomain) findFrontDomainFromListByStandardName(targetFrontDomains, domainName).clone();
				domain.setPackageToken(packageToken);
				datadomainStart = true;
				if ("{".equals(notions2.get(i + 2))) {
					domainStack.push("{");
				}
				i = i + 3;
				// continue;
			}

			if ("{".equals(notions2.get(i))) {
				if (!domainStackjOverflow) {
					domainStack.push("{");
				} else {
					domainStackjOverflow = false;
				}
				// continue;
			}

			if ("}".equals(notions2.get(i))) {
				if (!domainStack.empty()) {
					domainStack.pop();
				} else {
					domainStackjOverflow = true;
				}
				// continue;
				if (datadomainStart) {
					list.add(domain);
					datadomainStart = false;
				}
				if (i >= notions2.size() - 1) {
					return list;
				}
			}

			if (datadomainStart && "domainid".equals(notions2.get(i))) {
				if (notions2.get(i + 1).equals(":")) {
					domain.setFieldValue(notions2.get(i + 2), notions2.get(i + 3));
					i += 3;
					continue;
				}
			}

			if (datadomainStart && "domainname".equals(notions2.get(i))) {
				if (notions2.get(i + 1).equals(":")) {
					domain.setFieldValue(notions2.get(i + 2), notions2.get(i + 3));
					i += 3;
					continue;
				}
			}

			if (datadomainStart && "activefield".equals(notions2.get(i))) {
				if (notions2.get(i + 1).equals(":") && !isKeyword(notions2.get(i + 2))) {
					domain.setFieldValue(notions2.get(i + 2), notions2.get(i + 3));
					i += 3;
					continue;
				}
			}

			if (datadomainStart && "field".equals(notions2.get(i))) {
				if (notions2.get(i + 1).equals(":") && !isKeyword(notions2.get(i + 2))) {
					domain.setFieldValue(notions2.get(i + 2), notions2.get(i + 3));
					i += 3;
					continue;
				}
			}

			if (datadomainStart && "dropdown".equals(notions2.get(i))) {
				if (notions2.get(i + 1).equals(":") && !isKeyword(notions2.get(i + 2))
						&& !isKeyword(notions2.get(i + 3)) && !";".equals(notions2.get(i + 3)) && ";".equals(notions2.get(i + 4))) {
//					FrontField f = domain.getField(notions2.get(i + 2));
//					FrontDropdown dp = (FrontDropdown) f;
//					if (dp == null) throw new ValidateException("没有找到下拉列表对应字段！");
//					String fieldValue = notions2.get(i + 3);
//					if (!StringUtil.isBlank(fieldValue))
//						domain.setFieldValue(dp.getAliasName(), fieldValue);
//					else
//						domain.setFieldValue(dp.getAliasName(), fieldValue);
					i += 3;
				}else if (notions2.get(i + 1).equals(":") && !isKeyword(notions2.get(i + 2))&&";".equals(notions2.get(i + 3))) {
//					FrontField f = domain.getField(notions2.get(i + 2));
//					FrontDropdown dp = (FrontDropdown) f;
//					domain.setFieldValue(dp.getAliasName(), "");
					i += 2;
				}
				continue;
			}

			if ("manytomanyslave".equals(notions2.get(i))) {
				
				if (!notions2.get(i + 2).equals(";") && !notions2.get(i + 3).equals(";")) {
					for (FrontManyToMany mtm:domain.getManyToManies()){
						if (mtm.getSlaveAlias().equals(notions2.get(i + 2))) {
//							mtm.setMaster(domain);
//							mtm.setValues(notions2.get(i + 3));
//							mtm.setMasterValue(domain.getDomainId().getFieldValue());
//							mtm.setSlave((FrontDomain)findFrontDomainFromListByAliasOrName(domainList, mtm.getManyToManySalveName()).clone());
							i += 4;							
						}
					}
				}
				continue;
			}

			if (";".equals(notions2.get(i)))
				continue;
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("解析域对象错误。");
		throw new ValidateException(info);
	}

	public static boolean isKeyword(String notion) {
		if ("project".equals(notion) || "prism".equals(notion) || "domain".equals(notion) || "datadomain".equals(notion)
				|| "field".equals(notion) || "packagetoken".equals(notion) || "plural".equals(notion)
				|| "activefield".equals(notion) || "domainname".equals(notion) || "domainid".equals(notion)
				|| "prismdomain".equals(notion) || "dbname".equals(notion) || "emptypassword".equals(notion)
				|| "call".equals(notion) || "magic".equals(notion) || "domainlabel".equals(notion)
				|| "labelfield".equals(notion) || "manytomanyslave".equals(notion) || "dropdown".equals(notion)
				||"manytomanyslavelabel".equals(notion)||"title".equals(notion)||"subtitle".equals(notion)||"footer".equals(notion)
				|| "resolution".equals(notion)||"crossorigin".equals(notion))
			return true;
		else
			return false;
	}

	public static int countFrontDomains(List<String> notions) {
		int count = 0;
		for (String s : notions) {
			if (s.equals("domain"))
				count++;
		}
		return count;
	}

	public static int countFrontPrisms(List<String> notions) {
		int count = 0;
		for (String s : notions) {
			if (s.equals("prism"))
				count++;
		}
		return count;
	}

	public static boolean containsRoundAndSquareBrackets(String source) {
		return source.contains("[") || source.contains("]") || source.contains("(") || source.contains(")");
	}

	public int countFrontDomain(List<String> notions) {
		int count = 0;
		for (String notion : notions) {
			if (notion.contains("domain"))
				count++;
		}
		return count;
	}

	public static FrontProject callMagic(FrontProject project, List<FrontDomain> domains) throws Exception {
		List<FrontPrism> prisms = generateFrontPrismsByFrontDomains(domains,project);
		project.setPrisms(prisms);
		project.putAllDomains(domains);
		return project;
	}

	public static void decorateFrontDropdowns(List<FrontDomain> domainList) throws ValidateException {
		for (FrontDomain d : domainList) {
			for (FrontField f : d.getFieldsWithoutId()) {
				if (f instanceof FrontDropdown) {
					FrontDropdown dp = (FrontDropdown) f;
					Set<FrontDomain> domainSet = new TreeSet<FrontDomain>();
					domainSet.addAll(domainList);						
					FrontDomain t = DomainUtil.findDomainInSet(domainSet, dp.getTargetName());
					dp.decorate(t);
				}
			}
		}
	}
	
	public static void decorateFrontManyToManySlaves(List<FrontDomain> domainList) throws ValidateException {
		for (FrontDomain d : domainList) {
			for (FrontManyToMany mtm: d.getManyToManies()) {
				String slaveAlias = mtm.getSlaveAlias();
				if (mtm.getSlave()==null&&!StringUtil.isBlank(slaveAlias)) {
					FrontDomain slave = (FrontDomain)findFrontDomainFromListByStandardName(domainList, mtm.getManyToManySalveName()).clone();
					slave.setAlias(slaveAlias);
					mtm.setSlave(slave);
				}
			}
		}
	}

	public static boolean locateCallMagic(List<String> notions) {
		if (notions.contains("call") && notions.contains("magic"))
			return true;
		else
			return false;
	}

	public static List<FrontPrism> generateFrontPrismsByFrontDomains(List<FrontDomain> domains,FrontProject project) throws Exception {
		List<FrontPrism> prisms = new ArrayList<FrontPrism>();
		for (FrontDomain d : domains) {
			d.decorateDomainWithLabels();
			FrontPrism p = new FrontPrism();
			p.setPackageToken(d.getPackageToken());
			p.setStandardName(d.getCapFirstDomainName() + "FrontPrism");
			p.setDomain(d);
			p.setProjectDomains(domains);
			p.setTitle(project.getTitle());
			p.setSubTitle(project.getSubTitle());
			p.setFooter(project.getFooter());
			p.generatePrismFromDomain();
			prisms.add(p);
		}
		return prisms;
	}

	public static ValidateInfo validateFrontDomainsAndFrontPrisms(List<FrontDomain> domains, List<FrontPrism> prisms) {
		ValidateInfo validateInfo1 = validateFrontDomains(domains);
		ValidateInfo validateInfo2 = validateFrontPrisms(prisms);
		List<ValidateInfo> vList = new ArrayList<ValidateInfo>();
		vList.add(validateInfo1);
		vList.add(validateInfo2);
		ValidateInfo validateInfo = ValidateInfo.mergeValidateInfo(vList);
		return validateInfo;
	}

	public static ValidateInfo validateFrontDomains(List<FrontDomain> domains) {
		ValidateInfo validateInfo = new ValidateInfo();
		List<ValidateInfo> infos = new ArrayList<ValidateInfo>();
		infos.add(validateInfo);
		for (FrontDomain d : domains) {
			ValidateInfo vd = validateFrontDomain(d);
			infos.add(vd);
		}
		return ValidateInfo.mergeValidateInfo(infos);
	}

	public static ValidateInfo validateFrontPrisms(List<FrontPrism> prisms) {
		ValidateInfo validateInfo = new ValidateInfo();
		List<FrontPrism> targets = new ArrayList<FrontPrism>();
		for (FrontPrism fp:prisms) {
			if (!fp.getStandardName().equals(fp.getDomain().getStandardName() + "FrontPrism")) {
				validateInfo.addCompileWarning("棱柱" + fp.getStandardName() + "的域对象"
						+ fp.getDomain().getStandardName() + "没有正确设置。");
			}
		}
		return validateInfo;
	}

	public static ValidateInfo basicValidateFrontProject(FrontProject project) {
		List<FrontPrism> prisms = project.getPrisms();
		List<FrontDomain> domains = project.getDomains();
		return validateFrontDomainsAndFrontPrisms(domains, prisms);
	}

	public static ValidateInfo validateFrontDomain(FrontDomain domain) {
		ValidateInfo validateInfo = new ValidateInfo();
		if (StringUtil.isBlank(domain.getDomainId())) {
			validateInfo.addCompileError("域对象" + domain.getStandardName() + "的主键没有设置。");
		}
		if (StringUtil.isBlank(domain.getDomainName())) {
			validateInfo.addCompileError("域对象" + domain.getStandardName() + "的对象名字没有设置。");
		}
		if (StringUtil.isBlank(domain.getActive())) {
			validateInfo.addCompileError("域对象" + domain.getStandardName() + "的活跃字段没有设置。");
		}
		return validateInfo;
	}	
	
	public static void decorateMtmFrontDomainList(List<List<FrontDomain>> dataFrontDomainList,List<FrontDomain> allFrontDomainList) throws Exception{
		for (List<FrontDomain> targets:dataFrontDomainList){
			for (FrontDomain targetFrontDomain: targets){
				for (FrontManyToMany mtm:targetFrontDomain.getManyToManies()){
					mtm.setSlave(SGSCompiler.findFrontDomainFromListByStandardName(allFrontDomainList,mtm.getManyToManySalveName()));
				}
			}
		}
	}
}
